package locsi;

import java.awt.Color;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import view.UtilityConstants;

public final class UserSettings {

	/**
	 * Regulaerer Ausdruck der einen Zahlenwert von 0-255 in Stringform
	 * repraesentiert
	 */
	private static final String regexColorRange = "[0-2]?[0-5]?[0-5]+|[0-2]?[0-4]?[0-9]+";

	/**
	 * Gibt an, ob das Laden der Einstellungedatei am Anfang erfolgreich war
	 * oder nicht
	 */
	public static boolean loadingWasSuccessful = false;

	/**
	 * Pfad zur Settingsdatei
	 */
	private static final String pathToSettingFile = "settings"
			+ UtilityConstants.SEPARATOR + "userSettings.ini";

	/**
	 * Vergroesserung des klickbaren Bereichs bei Inputs/Outputs
	 */
	public static int inputOutputOffset = 5;
	private static final int defaultInputOutputOffset = 5;

	/**
	 * Farbe fuer Eingaenge Default: Color.ORANGE
	 */
	public static Color inputColor = Color.ORANGE;
	private static final Color defaultInputColor = Color.ORANGE;

	/**
	 * Farbe fuer Ausgaenge Default: Color(51, 153, 255)
	 */
	public static Color outputColor = new Color(51, 153, 255);
	private static final Color defaultOutputColor = new Color(51, 153, 255);

	/**
	 * Flag ob das Bild fuer selbstdefinierte Bauteile gezeichnet werden soll
	 * oder nicht Default: true
	 */
	public static boolean paintSDPicture = true;
	private static final boolean defaultPaintSDPicture = true;

	/**
	 * Flag ob STRG gedrueckt sein muss um das Bild anzuzeigen Default: false
	 */
	public static boolean needControlDownForPicture = false;
	private static final boolean defaultNeedControlDownForPicture = false;

	/**
	 * Flag ob der Tooltip fuer Eingangs/Ausgangsnamen angezeigt werden soll
	 * Default: true
	 */
	public static boolean showInOutTooltip = true;
	private static final boolean defaultShowInOutTooltip = true;

	/**
	 * Flag ob in den paintComponents Kantenglaettung aktiviert sein soll oder
	 * nicht Default: true
	 */
	public static boolean doAntiAlias = true;
	private static final boolean defaultDoAntiAlias = true;

	/**
	 * Flag ob beim Laden einer Schaltung diese validiert werden soll Werte: -1
	 * = nie validieren, 0 = nachfragen, 1 = immer validieren Default: 0 =
	 * nachfragen
	 */
	public static int askForValidateMode = 0;
	private static final int defaultAskForValidateMode = 0;

	/**
	 * Flag ab wieviel Elementen die Schaltungsinformationen nicht mehr komplett
	 * ausgerechnet werden (Laufzeit) Default: 500
	 */
	public static int maxElemCircuitInfo = 500;
	private static int defaultMaxElemCircuitInfo = 500;

	/**
	 * Flag ab wieviel Elementen die Ueberschneidungsfreiheit nichtmehr
	 * gewaehrleistet wird Default: 10000
	 */
	public static int maxElemNoIntersect = 10000;
	private static int defaultMaxElemNoIntersect = 10000;

	/**
	 * Gibt das momentan ausgewaehlte Look&Feel an
	 */
	public static String actLookAndFeel = UIManager
			.getCrossPlatformLookAndFeelClassName();
	private static String defaultLookAndFeel = UIManager
			.getCrossPlatformLookAndFeelClassName();

	/**
	 * Gibt an ob das haessliche oder das schoene Lampendesign verwendet werden
	 * soll
	 */
	public static boolean uglyLamp = true;

	/**
	 * Privater Konstruktor damit Klasse nicht instanziert werden kann
	 */
	private UserSettings() {
	}

	/**
	 * Laedt die settings-Datei um folgende Benutzereinstellungen zu setzen: -
	 * Farbe der Eingaenge - Farbe der Ausgaenge - Flag ob Bild der
	 * selbstdefinierten Bauteile gezeichnet werden soll - Flag ob zum anzeigen
	 * des selbstdefinierten Bauteils STRG gedrueckt sein muss - Flag ob die
	 * Tooltips mit den Namen der Ein/Ausgaenge der selbstdefinierten Bauteile
	 * angezeigt werden soll oder nicht
	 * 
	 * Wenn die Datei nicht vorhanden bzw fehlerhaft ist werden sofort die
	 * Standardeinstellungen geladen
	 * 
	 * @return true, wenn das laden erfolgreich war. false bei einem Fehler und
	 *         somit die Standardeinstellungen geladen wurden
	 */
	public static boolean loadSettingsFile() {
		try {
			File setFile = new File(pathToSettingFile);
			if (!setFile.exists()) {
				restoreDefaultSettings();
				return false;
			}
			BufferedReader reader = new BufferedReader(new FileReader(setFile));
			String line = reader.readLine();

			if (line == null) {
				restoreDefaultSettings();
				return false;
			}

			while (line != null) {
				String[] lineSplit = line.split("=");
				if (lineSplit.length != 2) {
					restoreDefaultSettings();
					return false;
				}
				String field = lineSplit[0];
				String value = lineSplit[1];
				if (field.equals("inputColor")) {
					String[] values = value.split(",");

					// hier wird gecheckt, ob 3 werte angegeben sind, und ob sie
					// im richtigen bereich liegen (0-255 mit regex)
					if (values.length == 3
							&& values[0].matches(regexColorRange)
							&& values[1].matches(regexColorRange)
							&& values[2].matches(regexColorRange)) {
						int red = Integer.parseInt(values[0]);
						int green = Integer.parseInt(values[1]);
						int blue = Integer.parseInt(values[2]);
						inputColor = new Color(red, green, blue);
					} else {
						restoreDefaultSettings();
						return false;
					}
				} else if (field.equals("outputColor")) {
					String[] values = value.split(",");

					// hier wird gecheckt, ob 3 werte angegeben sind, und ob sie
					// im richtigen bereich liegen (0-255 mit regex)
					if (values.length == 3) {
						if (values[0].matches(regexColorRange)
								&& values[1].matches(regexColorRange)
								&& values[2].matches(regexColorRange)) {
							int red = Integer.parseInt(values[0]);
							int green = Integer.parseInt(values[1]);
							int blue = Integer.parseInt(values[2]);
							outputColor = new Color(red, green, blue);
						}
					} else {
						restoreDefaultSettings();
						return false;
					}
				} else if (field.equals("paintSDPicture")) {
					if (value.equals("true")) {
						paintSDPicture = true;
					} else if (value.equals("false")) {
						paintSDPicture = false;
					} else {
						restoreDefaultSettings();
						return false;
					}
				} else if (field.equals("showInOutTooltip")) {
					if (value.equals("true")) {
						showInOutTooltip = true;
					} else if (value.equals("false")) {
						showInOutTooltip = false;
					} else {
						restoreDefaultSettings();
						return false;
					}
				} else if (field.equals("needControlDownForPicture")) {
					if (value.equals("true")) {
						needControlDownForPicture = true;
					} else if (value.equals("false")) {
						needControlDownForPicture = false;
					} else {
						restoreDefaultSettings();
						return false;
					}
				} else if (field.equals("maxElemCircuitInfo")) {
					if (value.matches("[0-9]+")) {
						maxElemCircuitInfo = Integer.parseInt(value);
					} else {
						restoreDefaultSettings();
						return false;
					}
				} else if (field.equals("doAntiAlias")) {
					if (value.equals("true")) {
						doAntiAlias = true;
					} else if (value.equals("false")) {
						doAntiAlias = false;
					} else {
						restoreDefaultSettings();
						return false;
					}
				} else if (field.equals("maxElemNoIntersect")) {
					if (value.matches("[0-9]+")) {
						maxElemNoIntersect = Integer.parseInt(value);
					} else {
						restoreDefaultSettings();
						return false;
					}
				} else if (field.equals("inputOutputOffset")) {
					if (value.matches("[0-9]|10")) {
						inputOutputOffset = Integer.parseInt(value);
					} else {
						restoreDefaultSettings();
						return false;
					}
				} else if (field.equals("askForValidateMode")) {
					if (value.matches("-1|0|1")) {
						askForValidateMode = Integer.parseInt(value);
					} else {
						restoreDefaultSettings();
						return false;
					}
				} else if (field.equals("actLookAndFeel")) {
					actLookAndFeel = value;
					try {
						UIManager.setLookAndFeel(UserSettings.actLookAndFeel);
					} catch (ClassNotFoundException e) {
						actLookAndFeel = defaultLookAndFeel;
						System.out.println("Look&Feel konnte nicht gefunden werden. Standarddesign geladen");
					} catch (InstantiationException e) {
						actLookAndFeel = defaultLookAndFeel;
						System.out.println("Look&Feel konnte nicht gefunden werden. Standarddesign geladen");
					} catch (IllegalAccessException e) {
						actLookAndFeel = defaultLookAndFeel;
						System.out.println("Look&Feel konnte nicht gefunden werden. Standarddesign geladen");
					} catch (UnsupportedLookAndFeelException e) {
						actLookAndFeel = defaultLookAndFeel;
						System.out.println("Look&Feel konnte nicht gefunden werden. Standarddesign geladen");
					}
				}
				line = reader.readLine();
			}
		} catch (IOException e) {
			restoreDefaultSettings();
			e.printStackTrace();
			return false;
		}
		return true;
	}

	/**
	 * Schreibt die momentanen Einstellungen in die settingsDatei
	 */
	public static void writeSettingsFile() {
		File file = new File(pathToSettingFile);
		try {
			file.getParentFile().mkdir();
			file.createNewFile();
			StringBuilder builder = new StringBuilder();
			builder.append("inputColor=" + inputColor.getRed() + ","
					+ inputColor.getGreen() + "," + inputColor.getBlue()
					+ UtilityConstants.NEWLINE);
			builder.append("outputColor=" + outputColor.getRed() + ","
					+ outputColor.getGreen() + "," + outputColor.getBlue()
					+ UtilityConstants.NEWLINE);
			builder.append("paintSDPicture=" + paintSDPicture
					+ UtilityConstants.NEWLINE);
			builder.append("showInOutTooltip=" + showInOutTooltip
					+ UtilityConstants.NEWLINE);
			builder.append("needControlDownForPicture="
					+ needControlDownForPicture + UtilityConstants.NEWLINE);
			builder.append("maxElemCircuitInfo=" + maxElemCircuitInfo
					+ UtilityConstants.NEWLINE);
			builder.append("doAntiAlias=" + doAntiAlias
					+ UtilityConstants.NEWLINE);
			builder.append("maxElemNoIntersect=" + maxElemNoIntersect
					+ UtilityConstants.NEWLINE);
			builder.append("inputOutputOffset=" + inputOutputOffset
					+ UtilityConstants.NEWLINE);
			builder.append("askForValidateMode=" + askForValidateMode
					+ UtilityConstants.NEWLINE);
			builder.append("actLookAndFeel=" + actLookAndFeel
					+ UtilityConstants.NEWLINE);
			FileWriter writer = new FileWriter(file);
			writer.write(builder.toString());
			writer.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Diese Methode stellt die Standardeinstellungen wieder her.
	 */
	public static void restoreDefaultSettings() {
		inputColor = defaultInputColor;
		outputColor = defaultOutputColor;
		paintSDPicture = defaultPaintSDPicture;
		showInOutTooltip = defaultShowInOutTooltip;
		needControlDownForPicture = defaultNeedControlDownForPicture;
		maxElemCircuitInfo = defaultMaxElemCircuitInfo;
		doAntiAlias = defaultDoAntiAlias;
		maxElemNoIntersect = defaultMaxElemNoIntersect;
		inputOutputOffset = defaultInputOutputOffset;
		askForValidateMode = defaultAskForValidateMode;
		actLookAndFeel = defaultLookAndFeel;
	}

}
